

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package pl.put.dcs_modeler.visualModelEditor.windowComponenets;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.io.Serializable;
import java.util.Set;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import org.openide.cookies.SaveCookie;
import org.openide.filesystems.FileAttributeEvent;
import org.openide.filesystems.FileChangeListener;
import org.openide.filesystems.FileEvent;
import org.openide.filesystems.FileRenameEvent;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.openide.windows.TopComponent;
//import org.openide.util.Utilities;
import pl.put.dcs_modeler.fileTypeDataLoader.DCSComputingModelDataObject;
import pl.put.dcs_modeler.visualModelEditor.scene.CFMScene;
import org.openide.windows.CloneableTopComponent;
import pl.put.dcs.core.utils.serializer.SerializeManager;
import pl.put.dcs_modeler.visualModelEditor.EditedProjectSingleton;
import pl.put.dcs_modeler.visualModelEditor.palette.PaletteSupport;
import pl.put.dcs_modeler.visualModelEditor.propertiesEditor.editors.ComputingObjectPropertyEditor;
import pl.put.dcs_modeler.visualModelEditor.propertiesEditor.editors.ModelPropertyEditor;
import pl.put.model.flowModel.flowComputingObjectElement.FlowComputingObjectElement;

/**
 * Top component which displays something.
 */
public class CFMWindowTopComponent extends CloneableTopComponent 
{
    public static Logger log = Logger.getLogger( CFMWindowTopComponent.class.getName() );
    private static CFMWindowTopComponent instance;
    private DCSComputingModelDataObject dataObject;
    private CFMScene cfmScene;
    private SaveNode saveNode;
    private boolean isJustSaved = false;
    /** path to the icon used by the component and its open action */
//    static final String ICON_PATH = "SET/PATH/TO/ICON/HERE";

    private static final String PREFERRED_ID = "CFMWindowTopComponent";
    private Project project;

    private void CFMWindowTopComponent( ) 
    {

        cfmScene = new CFMScene( this.dataObject );
        SerializeManager sm = new SerializeManager();
        cfmScene.addPropertyChangeListener( "selectedSceneComputingObject", new SceneComputingObjectPropertyChangeListener() );
        cfmScene.addPropertyChangeListener( "isModified", new PropertyChangeListener()
                                        {
                                            @Override
                                            public void propertyChange( PropertyChangeEvent evt )
                                            {
                                                //log.info( "save!!!!!!!!!!!!!");
                                                saveNode.fire( ( ( Boolean )evt.getNewValue() ).booleanValue() );
                                            }
                                        } );
        initComponents();
        setName(NbBundle.getMessage(CFMWindowTopComponent.class, "CTL_CFMWindowTopComponent"));
        setToolTipText(NbBundle.getMessage(CFMWindowTopComponent.class, "HINT_CFMWindowTopComponent"));
        jScrollPane1.setViewportView( cfmScene.createView() );
        ModelPropertyEditor mpe = new ModelPropertyEditor();
        associateLookup( Lookups.fixed(  new Object[] { PaletteSupport.createPalette(), saveNode } ) );
        //ComputingObjectPropertyEditor cope = new ComputingObjectPropertyEditor();
        project = FileOwnerQuery.getOwner( dataObject.getPrimaryFile() );


        dataObject.getPrimaryFile().addFileChangeListener( new FileChangeListener() {

            @Override
            public void fileFolderCreated( FileEvent fe )
            {
                //throw new UnsupportedOperationException( "Not supported yet." );
            }

            @Override
            public void fileDataCreated( FileEvent fe )
            {
                
            }

            @Override
            public void fileChanged( FileEvent fe )
            {
              
            }

            @Override
            public void fileDeleted( FileEvent fe )
            {
                JOptionPane.showMessageDialog( null, "Warning! Flow model object has been deleted." );
            }

            @Override
            public void fileRenamed( FileRenameEvent fe )
            {
                //throw new UnsupportedOperationException( "Not supported yet." );
            }

            @Override
            public void fileAttributeChanged( FileAttributeEvent fe )
            {
                //throw new UnsupportedOperationException( "Not supported yet." );
            }
        });
        
    }

    /*
    private void fileIsChanged()
    {
        if ( !isJustSaved )
        {
            int option = JOptionPane.showConfirmDialog( null, "Scene file is changed. Reload the scene?", "Scene file changed!", JOptionPane.YES_NO_OPTION );
            if ( option == JOptionPane.YES_OPTION )
            {
                reloadScene();
            }
        }
        else
        {
            isJustSaved = false;
        }

    }
*/
    public  CFMWindowTopComponent( DCSComputingModelDataObject dCSComputingModelDataObject )
    {
        
        dataObject = dCSComputingModelDataObject;
        //System.out.print( dataObject.getFileContent() );

        //dCSComputingModelDataObject.setModified( true );
        saveNode = new SaveNode();
        CFMWindowTopComponent();
       /* setActivatedNodes( new Node[]
                {
                    saveNode = new DummyNode()
                } );
*/
        
        reloadScene();
        saveNode.fire( false );
        
    }

    public void save()
    {
        saveNode.save();
    }


    public void reloadScene()
    {
        
        // UWAGA!!! Deserializacja przez usSerializeFromFile blednie dziala z powodu XStreem. Po prostu ta biblioteka czesto blokuje
        // plik i w ogle go nie zwalnia. Pozniej nic z plikiem nie mozna zrobic. Dlaczego tak jest - brak info
        // @todo poprawic

        try
        {
            cfmScene.deserialize( dataObject.getFileContent() );
        }
        catch ( Exception e )
        {
            log.warning( e.getMessage() );
            e.printStackTrace();
        }
       
    }
    
    
    public void clearScene()
    {
        cfmScene.clearScene();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents()
    {

        jScrollPane1 = new javax.swing.JScrollPane();

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 383, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
        );
    }// </editor-fold>//GEN-END:initComponents


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JScrollPane jScrollPane1;
    // End of variables declaration//GEN-END:variables
    /**
     * Gets default instance. Do not use directly: reserved for *.settings files only,
     * i.e. deserialization routines; otherwise you could get a non-deserialized instance.
     * To obtain the singleton instance, use {@link findInstance}.
     */
    public static synchronized CFMWindowTopComponent getDefault()
    {
        if ( instance == null )
        {
            //instance = new CFMWindowTopComponent( );
        }
        log.info( "iop");
        return instance;
    }
    
    /**
     * Czy zostalo juz otworzone okno
     * @return Boolean true, jezeli istnieje okno
     */
    public static synchronized Boolean isInstaceExist()
    {
        if ( instance ==  null )
        {
            return false;
        }
        return true;
    }

    public boolean isBelongToThisTopComponent( DCSComputingModelDataObject dCSComputingModelDataObject )
    {
        if ( this.dataObject.equals( dCSComputingModelDataObject ) )
        {
            return true;
        }
        return false;
    }

    /**
     * Obtain the CFMWindowTopComponent instance. Never call {@link #getDefault} directly!
     */
    public static synchronized CFMWindowTopComponent findInstance( DCSComputingModelDataObject dCSComputingModelDataObject )
    {
        Set< TopComponent > tcs = TopComponent.getRegistry().getOpened();
        for ( TopComponent tc : tcs )
        {
            if ( ( tc instanceof CFMWindowTopComponent ) && ( ( ( CFMWindowTopComponent ) tc ).isBelongToThisTopComponent( dCSComputingModelDataObject ) ) )
            {
                return ( CFMWindowTopComponent )tc;
            }
        }
        return new CFMWindowTopComponent( dCSComputingModelDataObject );
    }

    @Override
    public int getPersistenceType()
    {
        return TopComponent.PERSISTENCE_ALWAYS;
    }

    @Override
    public void componentOpened()
    {
        // TODO add custom code on component opening
    }

    @Override
    public void componentClosed()
    {
        // TODO add custom code on component closing
    }

    /** replaces this in object stream */
    @Override
    public Object writeReplace()
    {
        return new ResolvableHelper();
    }

    @Override
    protected String preferredID()
    {
        return PREFERRED_ID;
    }

    public CFMScene getCfmScene()
    {
        return cfmScene;
    }

    public void setCfmScene( CFMScene cfmScene )
    {
        this.cfmScene = cfmScene;
    }

    final static class ResolvableHelper implements Serializable
    {

        private static final long serialVersionUID = 1L;

        public Object readResolve()
        {
            return CFMWindowTopComponent.getDefault();
        }
    }
     
    private class SaveNode extends AbstractNode
    {

        private boolean changed = false;
        SaveCookieImpl impl;

        public SaveNode()
        {

            super(Children.LEAF);
            impl = new SaveCookieImpl();

        }
        
        

        public void fire( boolean modified )
        {
            if ( modified )
            {
                getCookieSet().assign( SaveCookie.class, impl );
                dataObject.setModified( true );
            }
            else
            {
                getCookieSet().assign( SaveCookie.class  );
                dataObject.setModified( false );
            }
            
        }

        public void save()
        {
            try
            {
                impl.save();
            }
            catch ( IOException ex )
            {
                Exceptions.printStackTrace( ex );
            }
        }
    

        private class SaveCookieImpl implements SaveCookie
        {

            @Override
            public void save() throws IOException
            {
               // pozostawiam furtke, zeby w momencie rozbudowania tego TopComponent (np. dwie sceny w jednym) ten komponent decydowal o serializacji
               // calosci. Tworzone sa referencje, wiec nie jest to az tak duze obciazenia. Jednak najlepiej jest uzyc strumieni, ktorych wykorzystanie oferuje bezposrednio XPath w SerailizeManager
                // UWAGA!!! Wystepuje problem z blokowanie plikow przez XStream w wypadku wykorzystania jego mechanizmu zapisu
                isJustSaved = true;
                SerializeManager sm = new SerializeManager();
                String serializedModel = cfmScene.serialize();
                dataObject.writeString( serializedModel );
                
                dataObject.setModified( false );
                cfmScene.setSceneIsNotModified();
                isJustSaved = true;
                log.info( "save");
            }
        }
    }

    private class SceneComputingObjectPropertyChangeListener implements PropertyChangeListener
    {

        @Override
        public void propertyChange( PropertyChangeEvent evt )
        {
            
            FlowComputingObjectElement selectedCO = ( FlowComputingObjectElement )evt.getNewValue();
            ComputingObjectPropertyEditor propEdit = new ComputingObjectPropertyEditor( selectedCO, project );
            EditedProjectSingleton singleton = EditedProjectSingleton.getInstance();
            Project project = FileOwnerQuery.getOwner( dataObject.getPrimaryFile() );
            singleton.setProject( project );
            setActivatedNodes( new Node[]{ propEdit } );
        }
    }
}
